Completed
Push — master ( dc6599...122bc8 )
by Rafael S.
01:53
created

packer.js ➔ toBytes_   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
nc 4
dl 0
loc 1
c 0
b 0
f 0
cc 3
rs 10
nop 2
1
/*
2
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining
5
 * a copy of this software and associated documentation files (the
6
 * "Software"), to deal in the Software without restriction, including
7
 * without limitation the rights to use, copy, modify, merge, publish,
8
 * distribute, sublicense, and/or sell copies of the Software, and to
9
 * permit persons to whom the Software is furnished to do so, subject to
10
 * the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
25
/**
26
 * @fileoverview Function to serialize binary data.
27
 * @see https://github.com/rochars/byte-data
28
 */
29
30
import Integer from './integer.js';
31
import endianness from './endianness.js';
32
import {validateType} from './validation.js';
33
34
/**
35
 * @type {!Int8Array}
36
 * @private
37
 */
38
const int8_ = new Int8Array(8);
39
/**
40
 * @type {!Uint32Array}
41
 * @private
42
 */
43
const ui32_ = new Uint32Array(int8_.buffer);
44
/**
45
 * @type {!Float32Array}
46
 * @private
47
 */
48
const f32_ = new Float32Array(int8_.buffer);
49
/**
50
 * @type {!Float64Array}
51
 * @private
52
 */
53
const f64_ = new Float64Array(int8_.buffer);
54
/**
55
 * @type {Function}
56
 * @private
57
 */
58
let reader_;
59
/**
60
 * @type {Function}
61
 * @private
62
 */
63
let writer_;
64
/**
65
 * @type {Object}
66
 * @private
67
 */
68
let gInt_ = {};
69
70
/**
71
 * Validate the type and set up the packing/unpacking functions.
72
 * @param {!Object} theType The type definition.
73
 * @throws {Error} If the type definition is not valid.
74
 * @private
75
 */
76
export function setUp_(theType) {
77
  validateType(theType);
78
  theType.offset = theType.bits < 8 ? 1 : Math.ceil(theType.bits / 8);
79
  theType.be = theType.be || false;
80
  setReader(theType);
81
  setWriter(theType);
82
  gInt_ = new Integer(
83
    theType.bits == 64 ? 32 : theType.bits,
84
    theType.float ? false : theType.signed);
85
}
86
87
/**
88
 * Turn numbers to bytes.
89
 * @param {number} value The value to be packed.
90
 * @param {!Object} theType The type definition.
91
 * @param {!Uint8Array|!Array<number>} buffer The buffer to write the bytes to.
92
 * @param {number} index The index to start writing.
93
 * @param {number} len The end index.
94
 * @param {!Function} validate The function used to validate input.
95
 * @param {boolean} be True if big-endian.
96
 * @return {number} the new index to be written.
97
 * @private
98
 */
99
export function writeBytes_(value, theType, buffer, index, len, validate, be) {
100
  while (index < len) {
101
    validate(value, theType);
102
    index = writer_(buffer, value, index);
103
  }
104
  if (be) {
105
    endianness(
106
      buffer, theType.offset, index - theType.offset, index);
107
  }
108
  return index;
109
}
110
111
/**
112
 * Read int values from bytes.
113
 * @param {!Uint8Array} bytes An array of bytes.
114
 * @param {number} i The index to read.
115
 * @return {number}
116
 * @private
117
 */
118
function readInt_(bytes, i) {
119
  return gInt_.read(bytes, i);
120
}
121
122
/**
123
 * Read 1 16-bit float from bytes.
124
 * Thanks https://stackoverflow.com/a/8796597
125
 * @param {!Uint8Array} bytes An array of bytes.
126
 * @param {number} i The index to read.
127
 * @return {number}
128
 * @private
129
 */
130
function read16F_(bytes, i) {
131
  let int = gInt_.read(bytes, i);
132
  let exponent = (int & 0x7C00) >> 10;
133
  let fraction = int & 0x03FF;
134
  let floatValue;
135
  if (exponent) {
136
    floatValue =  Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
137
  } else {
138
    floatValue = 6.103515625e-5 * (fraction / 0x400);
139
  }
140
  return floatValue * (int >> 15 ? -1 : 1);
141
}
142
143
/**
144
 * Read 1 32-bit float from bytes.
145
 * @param {!Uint8Array} bytes An array of bytes.
146
 * @param {number} i The index to read.
147
 * @return {number}
148
 * @private
149
 */
150
function read32F_(bytes, i) {
151
  ui32_[0] = gInt_.read(bytes, i);
152
  return f32_[0];
153
}
154
155
/**
156
 * Read 1 64-bit float from bytes.
157
 * Thanks https://gist.github.com/kg/2192799
158
 * @param {!Uint8Array} bytes An array of bytes.
159
 * @param {number} i The index to read.
160
 * @return {number}
161
 * @private
162
 */
163
function read64F_(bytes, i) {
164
  ui32_[0] = gInt_.read(bytes, i);
165
  ui32_[1] = gInt_.read(bytes, i + 4);
166
  return f64_[0];
167
}
168
169
/**
170
 * Write a integer value to a byte buffer.
171
 * @param {!Uint8Array} bytes An array of bytes.
172
 * @param {number} number The number to write as bytes.
173
 * @param {number} j The index being written in the byte buffer.
174
 * @return {!number} The next index to write on the byte buffer.
175
 * @private
176
 */
177
function writeInt_(bytes, number, j) {
178
  return gInt_.write(bytes, number, j);
179
}
180
181
/**
182
 * Write one 16-bit float as a binary value.
183
 * @param {!Uint8Array} bytes An array of bytes.
184
 * @param {number} number The number to write as bytes.
185
 * @param {number} j The index being written in the byte buffer.
186
 * @return {number} The next index to write on the byte buffer.
187
 * @private
188
 */
189
function write16F_(bytes, number, j) {
190
  f32_[0] = number;
191
  let x = ui32_[0];
192
  let bits = (x >> 16) & 0x8000;
193
  let m = (x >> 12) & 0x07ff;
194
  let e = (x >> 23) & 0xff;
195
  if (e >= 103) {
196
    bits |= ((e - 112) << 10) | (m >> 1);
197
    bits += m & 1;
198
  }
199
  bytes[j++] = bits & 0xFF;
200
  bytes[j++] = bits >>> 8 & 0xFF;
201
  return j;
202
}
203
204
/**
205
 * Write one 32-bit float as a binary value.
206
 * @param {!Uint8Array} bytes An array of bytes.
207
 * @param {number} number The number to write as bytes.
208
 * @param {number} j The index being written in the byte buffer.
209
 * @return {number} The next index to write on the byte buffer.
210
 * @private
211
 */
212
function write32F_(bytes, number, j) {
213
  f32_[0] = number;
214
  return gInt_.write(bytes, ui32_[0], j);
215
}
216
217
/**
218
 * Write one 64-bit float as a binary value.
219
 * @param {!Uint8Array} bytes An array of bytes.
220
 * @param {number} number The number to write as bytes.
221
 * @param {number} j The index being written in the byte buffer.
222
 * @return {number} The next index to write on the byte buffer.
223
 * @private
224
 */
225
function write64F_(bytes, number, j) {
226
  f64_[0] = number;
227
  j = gInt_.write(bytes, ui32_[0], j);
228
  return gInt_.write(bytes, ui32_[1], j);
229
}
230
231
/**
232
 * Set the function to unpack the data.
233
 * @param {!Object} theType The type definition.
234
 * @private
235
 */
236
function setReader(theType) {
237
  if (theType.float) {
238
    if (theType.bits == 16) {
239
      reader_ = read16F_;
240
    } else if(theType.bits == 32) {
241
      reader_ = read32F_;
242
    } else if(theType.bits == 64) {
243
      reader_ = read64F_;
244
    }
245
  } else {
246
    reader_ = readInt_;
247
  }
248
}
249
250
/**
251
 * Set the function to pack the data.
252
 * @param {!Object} theType The type definition.
253
 * @private
254
 */
255
function setWriter(theType) {
256
  if (theType.float) {
257
    if (theType.bits == 16) {
258
      writer_ = write16F_;
259
    } else if(theType.bits == 32) {
260
      writer_ = write32F_;
261
    } else if(theType.bits == 64) {
262
      writer_ = write64F_;
263
    }
264
  } else {
265
    writer_ = writeInt_;
266
  }   
267
}
268
269
export {reader_};
270